﻿using System.Security.Authentication;
using WebSocketSharp;
using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;

namespace EdgeTTS.Net.Utils;

public class WebSocketClient
{
    private WebSocket? _ws;

    public WebSocketClient(string url)
    {
        // 创建无限容量的channel，确保消息不会丢失
        SetupWebSocketEvents(url);
    }

    private bool IsConnected { get; set; }
    public event EventHandler<MessageEventArgs>? OnMessageReceived;
    public event EventHandler<ErrorEventArgs>? OnErrorOccured;

    private void SetupWebSocketEvents(string url)
    {
        _ws = new WebSocket(url);
        const SslProtocols sslProtocolHack =
            (SslProtocols)(SslProtocolsHack.Tls12 | SslProtocolsHack.Tls11 | SslProtocolsHack.Tls);
        _ws.SslConfiguration.EnabledSslProtocols = sslProtocolHack;
        if (url.Contains("wss://"))
            _ws.SslConfiguration.ServerCertificateValidationCallback = (_, _, _, _) => true;

        _ws.OnOpen += (_, _) => { IsConnected = true; };
        _ws.OnClose += (_, e) =>
        {
            //TlsHandshakeFailure
            if (e.Code == 1015 && _ws.SslConfiguration.EnabledSslProtocols != sslProtocolHack)
            {
                // OnLog?.Invoke(new Log(LogLevel.Error, "ssl握手失败，正在尝试重新连接."));
                _ws.SslConfiguration.EnabledSslProtocols = sslProtocolHack;
                _ws.Connect();
            }
            else
            {
                IsConnected = false;
            }
        };
        _ws.OnMessage += (_, e) => OnMessageReceived?.Invoke(this, e);
        _ws.OnError += (_, e) => OnErrorOccured?.Invoke(this, e);
    }

    // 同步连接
    public void Connect()
    {
        if (_ws != null && !IsConnected)
            _ws.Connect();
    }

    // 同步发送消息
    public void Send(string message)
    {
        if (_ws != null && IsConnected)
            _ws.Send(message);
    }

    // 同步发送字节数组
    public void Send(byte[] data)
    {
        if (_ws != null && IsConnected)
            _ws.Send(data);
    }

    // 关闭连接
    public void Close(ushort code = 1000, string reason = "")
    {
        if (_ws != null && IsConnected)
            _ws.Close(code, reason);
    }

    [Flags]
    private enum SslProtocolsHack
    {
        Tls = 192,
        Tls11 = 768,
        Tls12 = 3072
    }
}